//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Reflection;
using System.Windows.Media;
using OpenLS.Core.Serialization;
using OpenLS.Drawing.Serialization;

namespace OpenLS.Drawing
{
    public abstract class ColorBase : IOfficeXmlSerializable, INotifyPropertyChanged
    {
        private readonly List<ColorTransform> _transforms = new List<ColorTransform>();

        public List<ColorTransform> Transforms
        {
            get { return _transforms; }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region IOfficeXmlSerializable Members

        void IOfficeXmlSerializable.ReadXml(ReadContext context)
        {
            ReadXmlCore(context);
        }

        void IOfficeXmlSerializable.WriteXml(WriteContext context)
        {
            WriteXmlCore(context);
        }

        #endregion

        public static ColorBase ReadOptionalColorAs(string name, ReadContext context)
        {
            if (context.ReaderLocalName != name)
                return null;
            using (var c = context.ReadAndSwitch(name, DrawingConstants.DrawingNamespaceUri, context.ForceNamespace))
            {
                return ReadColor(c);
            }
        }

        public static ColorBase ReadOptionalColor(ReadContext context)
        {
            switch (context.ReaderLocalName)
            {
                case "sysClr":
                    SystemColor sysColor = new SystemColor();
                    sysColor.ReadXmlCore(context);
                    return sysColor;
                case "srgbClr":
                    SRgbColor srgbColor = new SRgbColor();
                    srgbColor.ReadXmlCore(context);
                    return srgbColor;
                case "schemeClr":
                    ThemeColor sc = new ThemeColor();
                    sc.ReadXmlCore(context);
                    return sc;
                case "scrgbClr":
                    ScRgbColor ScRgbColor = new ScRgbColor();
                    ScRgbColor.ReadXmlCore(context);
                    return ScRgbColor;
                case "hslClr":
                    HslColor HslColor = new HslColor();
                    HslColor.ReadXmlCore(context);
                    return HslColor;
                case "prstClr":
                    PresetColor presetColor = new PresetColor();
                    presetColor.ReadXmlCore(context);
                    return presetColor;
                case null:
                    return null;
                default:
                    throw new NotSupportedException();
            }
        }

        public static ColorBase ReadColor(ReadContext context)
        {
            switch (context.ReaderLocalName)
            {
                case "sysClr":
                    SystemColor sysColor = new SystemColor();
                    sysColor.ReadXmlCore(context);
                    return sysColor;
                case "srgbClr":
                    SRgbColor srgbColor = new SRgbColor();
                    srgbColor.ReadXmlCore(context);
                    return srgbColor;
                case "schemeClr":
                    ThemeColor sc = new ThemeColor();
                    sc.ReadXmlCore(context);
                    return sc;
                case "scrgbClr":
                    ScRgbColor ScRgbColor = new ScRgbColor();
                    ScRgbColor.ReadXmlCore(context);
                    return ScRgbColor;
                case "hslClr":
                    HslColor HslColor = new HslColor();
                    HslColor.ReadXmlCore(context);
                    return HslColor;
                case "prstClr":
                    PresetColor presetColor = new PresetColor();
                    presetColor.ReadXmlCore(context);
                    return presetColor;
                default:
                    throw new NotSupportedException();
            }
        }

        internal void WriteTransforms(WriteContext c)
        {
            foreach (IOfficeXmlSerializable t in Transforms)
                c.WriteElement(t);
        }

        internal void ReadTransforms(ReadContext c)
        {
            ColorTransform e = ColorTransform.ReadTransform(c);
            while (e != null)
            {
                _transforms.Add(e);
                e = ColorTransform.ReadTransform(c);
            }
        }


        protected abstract Color ResolveRawColor(ColorScheme colorScheme);

        public Color ResolveColor(ColorScheme colorScheme)
        {
            Color c = ResolveRawColor(colorScheme);
            foreach (ColorTransform t in Transforms)
                c = t.Apply(c);
            return c;
        }


        internal void WriteXmlAs(WriteContext context, string name)
        {
            using (WriteContext c = context.WriteAndSwitch(name, DrawingConstants.DrawingNamespace))
            {
                WriteXmlCore(c);
            }
        }

        internal abstract void ReadXmlCore(ReadContext context);

        internal abstract void WriteXmlCore(WriteContext context);

        protected void NotifyPropertyChanged(string propertyName)
        {
            Contract.Requires(GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null);
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

        internal static ColorBase ReadColorAs(string name, ReadContext context)
        {
            using (var c = context.ReadAndSwitch(name, DrawingConstants.DrawingNamespaceUri, false))
            {
                return ReadColor(c);
            }
        }
    }
}